home *** CD-ROM | disk | FTP | other *** search
- /*
- * lib.c - a library of vector operations, a random number generator, and
- * object output routines.
- *
- * Version: 2.2 (11/17/87)
- * Author: Eric Haines, 3D/Eye, Inc.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #include "def.h"
- #include "lib.h"
-
- static texture_count = 0;
- /*
- * Normalize the vector (X,Y,Z) so that X*X + Y*Y + Z*Z = 1.
- *
- * The normalization divisor is returned. If the divisor is zero, no
- * normalization occurs.
- *
- */
- double
- lib_normalize_coord3(COORD4 *cvec)
- {
- double divisor;
-
-
- divisor = sqrt( (double)DOT_PRODUCT( (*cvec), (*cvec) ) ) ;
-
- if ( divisor != 0.0 ) {
- cvec->x /= divisor;
- cvec->y /= divisor;
- cvec->z /= divisor;
- }
-
- return( divisor );
- }
-
-
- /*
- * Set all matrix elements to zero.
- */
- void
- lib_zero_matrix(MATRIX mx )
- {
- int i, j ;
- for ( i = 0 ; i < 4 ; ++i ) {
- for ( j = 0 ; j < 4 ; ++j ) {
- mx[i][j] = 0.0 ;
- }
- }
- }
-
-
- /*
- * Create identity matrix.
- */
- void
- lib_create_identity_matrix(MATRIX mx)
- {
- int i;
-
-
- lib_zero_matrix( mx ) ;
- for ( i = 0 ; i < 4 ; ++i ) {
- mx[i][i] = 1.0 ;
- }
- }
-
- /* Create translation matrix */
- void
- lib_create_translate_matrix(MATRIX mx, COORD4 *vec)
- {
- int i;
- lib_create_identity_matrix(mx);
- mx[3][0] = vec->x;
- mx[3][1] = vec->y;
- mx[3][2] = vec->z;
- }
-
- /* Create translation matrix */
- void
- lib_create_scale_matrix(MATRIX mx, COORD4 *vec)
- {
- int i;
- lib_zero_matrix(mx);
- mx[0][0] = vec->x;
- mx[1][1] = vec->y;
- mx[2][2] = vec->z;
- }
-
- /*
- * Create a rotation matrix along the given axis by the given angle in radians.
- */
- void
- lib_create_rotate_matrix(MATRIX mx, int axis, double angle)
- {
- double cosine ;
- double sine ;
-
-
- lib_zero_matrix( mx ) ;
-
- cosine = cos( (double)angle ) ;
- sine = sin( (double)angle ) ;
-
- switch ( axis ) {
- case X_AXIS:
- mx[0][0] = 1.0 ;
- mx[1][1] = cosine ;
- mx[2][2] = cosine ;
- mx[1][2] = sine ;
- mx[2][1] = -sine ;
- break ;
- case Y_AXIS:
- mx[1][1] = 1.0 ;
- mx[0][0] = cosine ;
- mx[2][2] = cosine ;
- mx[2][0] = sine ;
- mx[0][2] = -sine ;
- break ;
- case Z_AXIS:
- mx[2][2] = 1.0 ;
- mx[0][0] = cosine ;
- mx[1][1] = cosine ;
- mx[0][1] = sine ;
- mx[1][0] = -sine ;
- break ;
- }
- mx[3][3] = 1.0 ;
- }
-
-
- /*
- * Create a rotation matrix along the given axis by the given angle in radians.
- * The axis is a set of direction cosines.
- */
- void
- lib_create_axis_rotate_matrix(MATRIX mx, COORD4 *rvec, double angle)
- {
- COORD4 axis ;
- double cosine ;
- double one_minus_cosine ;
- double sine ;
-
-
- lib_zero_matrix( mx ) ;
-
- COPY_COORD( axis, (*rvec) ) ;
-
- cosine = cos( (double)angle ) ;
- sine = sin( (double)angle ) ;
- one_minus_cosine = 1.0 - cosine ;
-
- mx[0][0] = SQR(axis.x) + (1.0 - SQR(axis.x)) * cosine ;
- mx[0][1] = axis.x * axis.y * one_minus_cosine + axis.z * sine ;
- mx[0][2] = axis.x * axis.z * one_minus_cosine - axis.y * sine ;
-
- mx[1][0] = axis.x * axis.y * one_minus_cosine - axis.z * sine ;
- mx[1][1] = SQR(axis.y) + (1.0 - SQR(axis.y)) * cosine ;
- mx[1][2] = axis.y * axis.z * one_minus_cosine + axis.x * sine ;
-
- mx[2][0] = axis.x * axis.z * one_minus_cosine + axis.y * sine ;
- mx[2][1] = axis.y * axis.z * one_minus_cosine - axis.x * sine ;
- mx[2][2] = SQR(axis.z) + (1.0 - SQR(axis.z)) * cosine ;
-
- mx[3][3] = 1.0 ;
- }
-
- /* Given a point and a direction, find the transform that brings a point
- in a canonical coordinate system into a coordinate system defined by
- that position and direction. */
- void
- lib_create_canonical_matrix(MATRIX trans, COORD4 *origin, COORD4 *up)
- {
- MATRIX trans1, trans2;
- COORD4 tmpv;
-
- /* Translate "origin" to <0, 0, 0> */
- lib_create_translate_matrix(trans1, origin);
-
- /* Determine the axis to rotate about */
- if (fabs(up->z) == 1.0)
- SET_COORD4(tmpv, 1.0, 0.0, 0.0, 1.0)
- else
- SET_COORD4(tmpv, -up->y, up->x, 0.0, 1.0)
- lib_normalize_coord3(&tmpv);
- lib_create_axis_rotate_matrix(trans2, &tmpv, acos(up->z));
- lib_matrix_multiply(trans, trans2, trans1);
- }
-
-
- /*
- * Multiply a 4 element vector by a matrix.
- */
- void
- lib_transform_coord(COORD4 *vres, COORD4 *vec, MATRIX mx)
- {
- vres->x =
- vec->x*mx[0][0] + vec->y*mx[1][0] + vec->z*mx[2][0] + vec->w*mx[3][0] ;
- vres->y =
- vec->x*mx[0][1] + vec->y*mx[1][1] + vec->z*mx[2][1] + vec->w*mx[3][1] ;
- vres->z =
- vec->x*mx[0][2] + vec->y*mx[1][2] + vec->z*mx[2][2] + vec->w*mx[3][2] ;
- vres->w =
- vec->x*mx[0][3] + vec->y*mx[1][3] + vec->z*mx[2][3] + vec->w*mx[3][3] ;
- }
-
-
- /*
- * Multiply two 4x4 matrices.
- */
- void
- lib_matrix_multiply(MATRIX mxres, MATRIX mx1, MATRIX mx2 )
- {
- int i, j;
- for ( i = 0; i < 4; i++ ) {
- for ( j = 0; j < 4; j++ ) {
- mxres[i][j] = mx1[i][0]*mx2[0][j] +
- mx1[i][1]*mx2[1][j] +
- mx1[i][2]*mx2[2][j] +
- mx1[i][3]*mx2[3][j] ;
- }
- }
- }
-
-
- /*
- * Rotate a vector pointing towards the major-axis faces (i.e. the major-axis
- * component of the vector is defined as the largest value) 90 degrees to
- * another cube face. Mod_face is a face number.
- *
- * If the routine is called six times, with mod_face=0..5, the vector will be
- * rotated to each face of a cube. Rotations are:
- * mod_face = 0 mod 3, +Z axis rotate
- * mod_face = 1 mod 3, +X axis rotate
- * mod_face = 2 mod 3, -Y axis rotate
- */
- void
- lib_rotate_cube_face(COORD4 *vec, int major_axis, int mod_face )
- {
- double swap ;
-
-
- mod_face = (mod_face+major_axis) % 3 ;
- if ( mod_face == 0 ) {
- swap = vec->x ;
- vec->x = -vec->y ;
- vec->y = swap ;
- }
- else if ( mod_face == 1 ) {
- swap = vec->y ;
- vec->y = -vec->z ;
- vec->z = swap ;
- }
- else {
- swap = vec->x ;
- vec->x = -vec->z ;
- vec->z = swap ;
- }
- }
-
-
- /*
- * Portable gaussian random number generator (from "Numerical Recipes", GASDEV)
- * Returns a uniform random deviate between 0.0 and 1.0. 'iseed' must be
- * less than M1 to avoid repetition, and less than (2**31-C1)/A1 [= 300718]
- * to avoid overflow.
- */
- #define M1 134456
- #define IA1 8121
- #define IC1 28411
- #define RM1 1.0/M1
-
- double
- lib_gauss_rand(long iseed)
- {
- double fac ;
- long ix1, ix2 ;
- double r ;
- double v1, v2 ;
-
-
- ix2 = iseed ;
-
- do {
- ix1 = (IC1+ix2*IA1) % M1 ;
- ix2 = (IC1+ix1*IA1) % M1 ;
- v1 = ix1 * 2.0 * RM1 - 1.0 ;
- v2 = ix2 * 2.0 * RM1 - 1.0 ;
- r = v1*v1 + v2*v2 ;
- } while ( r >= 1.0 ) ;
-
- fac = sqrt( (double)( -2.0 * log( (double)r ) / r ) ) ;
- return( v1 * fac ) ;
- }
-
-
-
-
- /* OUTPUT ROUTINES
- *
- * Files are output as lines of text. For each entity, the first line
- * defines its type. The rest of the first line and possibly other lines
- * contain further information about the entity. Entities include:
- *
- * "v" - viewing vectors and angles
- * "l" - positional light location
- * "b" - background color
- * "f" - object material properties
- * "c" - cone or cylinder primitive
- * "s" - sphere primitive
- * "p" - polygon primitive
- * "pp" - polygonal patch primitive
- */
-
- /*
- * Output viewpoint location. The parameters are:
- * From: the eye location.
- * At: a position to be at the center of the image. A.k.a. "lookat"
- * Up: a vector defining which direction is up.
- *
- * Note that no assumptions are made about normalizing the data (e.g. the
- * from-at distance does not have to be 1). Also, vectors are not
- * required to be perpendicular to each other.
- *
- * For all databases some viewing parameters are always the same:
- *
- * Viewing angle is defined as from the center of top pixel row to bottom
- * pixel row and left column to right column.
- * Yon is "at infinity."
- * Resolution is always 512 x 512.
- */
- void
- lib_output_viewpoint( from, at, up, angle, hither, aspect, resx, resy)
- COORD4 *from;
- COORD4 *at;
- COORD4 *up;
- double angle;
- double hither;
- double aspect;
- int resx;
- int resy;
- {
- printf( "viewpoint {\n" ) ;
- printf( " from <%g, %g, %g>\n", from->x, from->y, from->z);
- printf( " at <%g, %g, %g>\n", at->x, at->y, at->z);
- printf( " up <%g, %g, %g>\n", up->x, up->y, up->z);
- printf( " angle %g\n", angle);
- printf( " hither %g\n", hither);
- printf( " aspect %g\n", aspect);
- printf( " resolution %d, %d\n", resx, resy);
- printf( " }\n");
- }
-
-
- /*
- * Output light. A light is defined by position. All lights have the same
- * intensity.
- *
- */
- void
- lib_output_light(center_pt)
- COORD4 *center_pt ;
- {
- printf( "light <%g, %g, %g>\n", center_pt->x, center_pt->y, center_pt->z ) ;
- }
-
-
- /*
- * Output background color. A color is simply RGB (monitor dependent, but
- * that's life). The format is:
- * "b" red green blue
- */
- void
- lib_output_background_color( color )
- COORD4 *color ;
- {
- printf( "background <%g, %g, %g>\n", color->x, color->y, color->z ) ;
- }
-
- void
- lib_output_bounding_slab(COORD4 *dir)
- {
- printf("bounding_slab <%g, %g, %g>\n", dir->x, dir->y, dir->z);
- }
-
-
- /*
- * Output a color and shading parameters for the object in the format:
- * "f" red green blue Kd Ks Shine T index_of_refraction
- *
- * Kd is the diffuse component, Ks the specular, Shine is the Phong cosine
- * power for highlights, T is transmittance (fraction of light passed per
- * unit). 0 <= Kd <= 1 and 0 <= Ks <= 1, though it is not required that
- * Kd + Ks == 1.
- *
- * The fill color is used to color the objects following it until a new color
- * is assigned or the file ends.
- *
- * Returns the name of the texture that will be used
- */
- char *
- lib_output_color(color, ka, kd, ks, ang, r, t, i_of_r )
- COORD4 *color;
- double ka;
- double kd;
- double ks;
- double ang;
- double r;
- double t;
- double i_of_r;
- {
- char *txname = malloc(7*sizeof(char));
- if (txname == NULL) {
- printf("Failed to allocate texture name %d\n", texture_count);
- exit(1);
- }
- sprintf(txname, "txt%03d", texture_count++);
- txname[6] = '\0';
- printf("define %s\n", txname);
- printf("texture {\n");
- printf(" surface {\n");
- printf(" ambient <%g, %g, %g>, %g\n",
- color->x, color->y, color->z, ka);
- printf(" diffuse <%g, %g, %g>, %g\n",
- color->x, color->y, color->z, kd);
- printf(" specular white, %g\n", ks);
- printf(" microfacet Phong %g\n", ang);
- printf(" reflection white, %g\n", r);
- printf(" transmission white, %g, %g\n", t, i_of_r);
- printf(" }\n");
- printf(" }\n");
- return txname;
- }
-
-
- /*
- * Output cylinder or cone. A cylinder is defined as having a radius and an
- * axis defined by two points, which also define the top and bottom edge of the
- * cylinder. A cone is defined similarly, the difference being that the apex
- * and base radii are different. The apex radius is defined as being smaller
- * than the base radius. Note that the surface exists without endcaps.
- *
- * If format=OUTPUT_CURVES, output the cylinder/cone in format:
- * "c"
- * base.x base.y base.z base_radius
- * apex.x apex.y apex.z apex_radius
- *
- */
- void
- lib_output_cylcone( base_pt, apex_pt, texture_name)
- COORD4 *base_pt, *apex_pt;
- char *texture_name;
- {
- printf("object {\n");
- if (base_pt->w == apex_pt->w)
- printf(" cylinder <%g, %g, %g>, <%g, %g, %g>, %g\n",
- base_pt->x, base_pt->y, base_pt->z,
- apex_pt->x, apex_pt->y, apex_pt->z, apex_pt->w);
- else
- printf(" cone <%g, %g, %g>, %g, <%g, %g, %g>, %g\n",
- base_pt->x, base_pt->y, base_pt->z, base_pt->w,
- apex_pt->x, apex_pt->y, apex_pt->z, apex_pt->w);
- printf(" %s\n", texture_name);
- printf(" }\n");
- }
-
-
- /*
- * Output sphere. A sphere is defined by a radius and center position.
- */
- void
- lib_output_sphere( center, texture_name )
- COORD4 *center;
- char *texture_name;
- {
- printf("object {\n");
- printf(" sphere <%g, %g, %g>, %g\n",
- center->x, center->y, center->z, center->w);
- printf(" %s\n", texture_name);
- printf(" }\n");
- }
-
-
- /*
- * Output polygon. A polygon is defined by a set of vertices. With these
- * databases, a polygon is defined to have all points coplanar. A polygon has
- * only one side, with the order of the vertices being counterclockwise as you
- * face the polygon (right-handed coordinate system).
- *
- * The output format is always:
- * "p" total_vertices
- * vert1.x vert1.y vert1.z
- * [etc. for total_vertices polygons]
- *
- */
- void
- lib_output_polygon(tot_vert, vert, texture_name)
- int tot_vert;
- COORD4 *vert;
- char *texture_name;
- {
- int num_vert;
- printf("object {\n");
- printf(" polygon %d,\n", tot_vert);
- for (num_vert = 0; num_vert < tot_vert; num_vert++) {
- printf(" <%g, %g, %g>",
- vert[num_vert].x, vert[num_vert].y, vert[num_vert].z);
- if (num_vert < tot_vert-1)
- printf(",");
- printf("\n");
- }
- printf(" %s\n", texture_name);
- printf(" }\n");
- }
-
-
- /*
- * Output polygonal patch. A patch is defined by a set of vertices and their
- * normals. With these databases, a patch is defined to have all points
- * coplanar. A patch has only one side, with the order of the vertices being
- * counterclockwise as you face the patch (right-handed coordinate system).
- *
- * The output format is always:
- * "pp" total_vertices
- * vert1.x vert1.y vert1.z norm1.x norm1.y norm1.z
- * [etc. for total_vertices polygonal patches]
- *
- */
- void
- lib_output_polypatch(tot_vert, vert, norm, texture_name)
- int tot_vert;
- COORD4 *vert;
- COORD4 *norm;
- char *texture_name;
- {
- if (tot_vert != 3) {
- printf("Patches must have 3 vertices, input was %d\n", tot_vert);
- exit(1);
- }
- printf("object {\n");
- printf(" patch <%g, %g, %g>, <%g, %g, %g>, <%g, %g, %g>,\n",
- vert[0].x, vert[0].y, vert[0].z,
- norm[0].x, norm[0].y, norm[0].z,
- vert[1].x, vert[1].y, vert[1].z);
- printf(" <%g, %g, %g>, <%g, %g, %g>, <%g, %g, %g>\n",
- norm[1].x, norm[1].y, norm[1].z,
- vert[2].x, vert[2].y, vert[2].z,
- norm[2].x, norm[2].y, norm[2].z);
- printf(" %s\n", texture_name);
- printf(" }\n");
- }
-